Skip to content

Add email airdrop Motoko demo#4044

Draft
aterga wants to merge 3 commits into
mainfrom
claude/sweet-einstein-qzl4n3
Draft

Add email airdrop Motoko demo#4044
aterga wants to merge 3 commits into
mainfrom
claude/sweet-einstein-qzl4n3

Conversation

@aterga

@aterga aterga commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

What

A small self-contained Motoko demo (demos/email-airdrop/) that airdrops 1 ICP to each person who emails airdrop@<your-domain> with a valid request.

The rules (shown on the landing page, GET /)

An email is eligible when all hold:

  1. The Subject contains the sender's ICP address — a 64-hex account identifier, checksum-verified (CRC32).
  2. There is at least one Cc with a friend's address (a valid address that isn't the sender's).
  3. The body contains, as plain substrings, both the app link and a short participation phrase (substrings, because mail clients append signatures/footers/quoted text).

Plus: one airdrop per email address, ever; rewards are paid while funds last, otherwise the sender joins a FIFO waitlist that drains automatically (a timer) or on demand (triggerWaitlist) after a top-up; and every attempt is stored (email_address → last_rewarded_at_timestamp, attempt count, last outcome).

The key design point: canisters can't receive SMTP

There is no inbound mail server on the IC, so airdrop@<domain> can't be served by the canister directly. The intended wiring is an inbound-email provider (SendGrid Inbound Parse / Mailgun Routes / Cloudflare Email Worker) that POSTs the raw message to the canister's http_request_update endpoint (guarded by a shared secret, and ideally carrying the provider's DKIM verdict). A typed submitEmail entrypoint runs the same logic for local testing. This is all laid out in the README.

Files

  • main.mo — the persistent actor (eligibility, CRC32 address validation, ledger transfer, waitlist, timer, HTTP gateway + rules page).
  • icp.yaml — deploys it via the @dfinity/motoko recipe.
  • README.md — rules, architecture diagram, run/test instructions, threat model, and open questions.
  • sample-email.txt — a ready-to-POST raw message (with a checksum-valid address).

Verification

Type-checked and compiled to Wasm against mo:base, and the trickiest pieces were exercised in the Motoko interpreter:

  • a checksum-valid account id is found in the subject; a bad-checksum / missing one is rejected;
  • Cc a different friend passes, Cc only yourself / empty fails;
  • the raw-email parser correctly extracts From/To/Cc/Subject/DKIM/body (including Name <addr> and comma-separated Cc).

Open questions (also in the README)

This is a demo, intentionally not hardened. A few choices worth your call before going further: address format (legacy account id vs ICRC-1), one-time vs cooldown rewards, whether the Cc'd friend is a referral, requiring DKIM pass, and timer-poll vs operator-driven waitlist draining. Questions and suggestions very welcome.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits June 19, 2026 15:20
A small demo canister that airdrops 1 ICP to each user who emails
airdrop@<domain> with a valid request.

Eligibility (all required):
  - ICP address (64-hex account identifier, checksum-verified) in the Subject
  - at least one Cc with a friend's address
  - body contains the app link and a participation phrase (substring checks,
    since mail clients append footers/signatures)

Other behaviour:
  - one airdrop per email address, ever
  - rewards paid while funds last; otherwise senders join a FIFO waitlist that
    is drained automatically (timer) or on demand (triggerWaitlist) after a
    top-up
  - every attempt is stored: email_address -> last_rewarded_at_timestamp

Since the IC has no inbound SMTP, the intended wiring is an inbound-email
provider (SendGrid/Mailgun/Cloudflare Email Worker) that POSTs the raw message
to the canister's http_request_update endpoint (secret-guarded). A typed
submitEmail entrypoint exercises the same logic locally. The landing page
(GET /) shows the rules.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
The repo's format-check step runs Prettier over `demos`; reformat the
README so it matches Prettier's style.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
Comment thread demos/email-airdrop/sample-email.txt Outdated
Per review: prefix the sample Subject with "Airdrop invite " so it also
demonstrates that the ICP address is extracted as a token from within the
subject, not required to be the entire subject.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mm4BEJjsY8qctP4x8sU1Ju
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants